package storage

import (
	"data-process/logger"
	"data-process/utils"
	"encoding/json"
	"fmt"
	"os"
	"path"
	"strings"
)

type SpecificWrite interface {
	WriteDataToFile(data <-chan map[string]interface{}, keys []string)
}

type WriteFactory struct {
}

func NewFactory(format, fileName, basePath string) SpecificWrite {
	switch format {
	case CSV:
		return &CsvWrite{
			fileName: fileName,
			basePath: basePath,
		}
	case EXCEL:
		return &ExcelWrite{}
	case SQL:
		return &SqlWrite{
			fileName:  fileName,
			basePath:  basePath,
			tableName: fileName[:strings.Index(fileName, ".")],
		}
	case TXT:
		return &TxtWrite{
			fileName: fileName,
			basePath: basePath,
		}
	default:
		return &OtherWrite{}
	}
}

type CsvWrite struct {
	fileName string
	basePath string
}

func (c *CsvWrite) WriteDataToFile(data <-chan map[string]interface{}, keys []string) {
	logger.Infof("将数据写入文件: %s\n", fmt.Sprintf("%s%s", c.basePath, c.fileName))
	file, flag := openFile(c.fileName, c.basePath)
	defer file.Close()
	if !flag {
		return
	}
	for {
		select {
		case temp, ok := <-data:
			if ok {
				logger.Infof("正在写入数据：%v", temp)
				bytes, err := json.Marshal(utils.MapToValues(temp, keys))
				if err != nil {
					continue
				}
				s := string(bytes)
				file.WriteString(fmt.Sprintf("%v\n", s[1:len(s)-1]))
			} else {
				logger.Info("数据写入文件完成")
				return
			}
		}
	}
}

type ExcelWrite struct {
	StorageFile
}

func (e *ExcelWrite) WriteDataToFile(data <-chan map[string]interface{}, keys []string) {
	fmt.Println("将数据写入Excel文件")
}

type TxtWrite struct {
	fileName string
	basePath string
}

func (t *TxtWrite) WriteDataToFile(data <-chan map[string]interface{}, keys []string) {
	logger.Infof("将数据写入文件: %s\n", path.Join(t.basePath, t.fileName))
	file, flag := openFile(t.fileName, t.basePath)
	defer file.Close()
	if !flag {
		return
	}
	for {
		select {
		case temp, ok := <-data:
			if ok {
				logger.Infof("正在写入数据：%v", temp)
				bytes, err := json.Marshal(temp)
				if err != nil {
					continue
				}
				file.WriteString(fmt.Sprintf("%v\n", string(bytes)))
			} else {
				logger.Info("数据写入文件完成")
				return
			}
		}
	}

}

type SqlWrite struct {
	fileName  string
	basePath  string
	tableName string
}

func (s *SqlWrite) buildSQl(data map[string]interface{}) string {
	keys := make([]string, 0, len(data))
	values := make([]interface{}, 0, len(data))
	for k, v := range data {
		keys = append(keys, k)
		values = append(values, v)
	}
	fields, _ := json.Marshal(keys)
	datas, _ := json.Marshal(values)
	fieldStr := strings.ReplaceAll(string(fields), "\"", "")
	dataStr := strings.ReplaceAll(string(datas), "\"", "'")
	return fmt.Sprintf("insert into %s (%s) values (%s);\n", s.tableName, fieldStr[1:len(fieldStr)-1], dataStr[1:len(dataStr)-1])
}

func (s *SqlWrite) WriteDataToFile(data <-chan map[string]interface{}, keys []string) {
	logger.Infof("将数据写入文件: %s\n", path.Join(s.basePath, s.fileName))
	file, flag := openFile(s.fileName, s.basePath)
	defer file.Close()
	if !flag {
		return
	}
	for {
		select {
		case temp, ok := <-data:
			if ok {
				logger.Infof("正在写入数据：%v", temp)
				file.WriteString(s.buildSQl(temp))
			} else {
				logger.Info("数据写入文件完成")
				return
			}
		}
	}
}

type OtherWrite struct {
	StorageFile
}

func (o *OtherWrite) WriteDataToFile(data <-chan map[string]interface{}, keys []string) {
	fmt.Println("暂无支持的数据写入文件格式")
}

// 检查是文件目录否存在
func openFile(fileName, basePath string) (*os.File, bool) {
	_, err := os.Stat(basePath)
	if os.IsPermission(err) {
		logger.Fatalf("目录%s读写权限不足\n", basePath)
		return nil, false
	} else if os.IsNotExist(err) {
		logger.Fatalf("监测到目录[%s]不存在将创建该目录\n", basePath)
		if err = os.Mkdir(basePath, os.ModePerm); err != nil {
			logger.Fatalf("创建该目录[%s]失败\n", basePath)
			return nil, false
		}
	}
	file, err := os.OpenFile(path.Join(basePath, fileName), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)
	if err != nil {
		logger.Fatalf("打开文件[%s]失败:%v\n", path.Join(basePath, fileName), err.Error())
		return nil, false
	}
	return file, true
}
